﻿using System;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using ToQueryString.Helpers;

namespace ToQueryString.Tests
{
    [TestClass]
    public class UrlHelpersTests
    {
        [TestMethod]
        [ExpectedException(typeof(ArgumentNullException))]
        public void ToQueryString_NullObject_ShouldThrowArgumentNullException()
        {
            // arrange
            object nullObject = null;

            // act
            nullObject.ToQueryString();

            // assert is handled by ExpectedException
        }

        [TestMethod]
        public void ToQueryString_WhenIllegalCharacters_ShouldEscape()
        {
            // arrange
            var objectWithIllegalChars = new
            {
                illegalchars = @"/\?&=%æøå"
            };

            // act
            var actual = objectWithIllegalChars.ToQueryString();

            // assert
            var expected = "illegalchars=%2F%5C%3F%26%3D%25%C3%A6%C3%B8%C3%A5";
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ToQueryString_WhenIllegalCharactersInList_ShouldReturnCommaBetweenEscapedValuesInArray()
        {
            // arrange
            var objectWithIllegalCharactersList = new
            {
                charlist = new List<char>() { 'æ', 'ø', 'å' }
            };

            // act
            var actual = objectWithIllegalCharactersList.ToQueryString();

            // assert
            var expected = "charlist=%C3%A6%2C%C3%B8%2C%C3%A5";
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ToQueryString_MultipleProperties_ShouldAmpersandSeparated()
        {
            // arrange
            var objectWithMultipleProperties = new
            {
                prop1 = "no1",
                prop2 = 2,
                prop3 = false
            };

            // act
            var actual = objectWithMultipleProperties.ToQueryString();

            // assert
            var expected = "prop1=no1&prop2=2&prop3=False";
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ToQueryString_IntArray_ShouldCommaSeparated()
        {
            // arrange
            var objectWithArray = new
            {
                ints = new[] { 1, 2, 3 }
            };

            // act
            var actual = objectWithArray.ToQueryString();

            // assert
            var expected = "ints=1%2C2%2C3";
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ToQueryString_IntList_ShouldCommaSeparated()
        {
            // arrange
            var objectWithList = new
            {
                ints = new List<int>() { 1, 2, 3 }
            };

            // act
            var actual = objectWithList.ToQueryString();

            // assert
            var expected = "ints=1%2C2%2C3";
            Assert.AreEqual(expected, actual);
        }
       
        [TestMethod]
        public void ToQueryString_WhenSeparatorIsDash_ShouldReturnDashBetweenValuesInCollections()
        {
            // arrange
            var objectWithCollection = new
            {
                collection = new[] { "a", "b", "c" }
            };

            // act
            var actual = objectWithCollection.ToQueryString("-");

            // assert
            var expected = "collection=a-b-c";
            Assert.AreEqual(expected, actual);
        }

        [TestMethod]
        public void ToQueryString_WhenVariableOrPrivateGetter_ShouldIgnore()
        {
            // arrange            
            var objectWithMixedAccessors = new MixedAccessorClassTest("public", "private", "variable");

            // act
            var actual = objectWithMixedAccessors.ToQueryString();

            // assert
            var expected = "PublicProperty=public";
            Assert.AreEqual(expected, actual);
        }
    }
}
